use async_graphql::*;
use async_graphql::connection::{Connection, EmptyFields};
use meilisearch_sdk::client::Client;
use sea_orm::DatabaseConnection;
use sea_orm::prelude::Decimal;
use crate::entity::product_main;
use crate::entity::product_specification;
use crate::handler::product_handler::{create_product, delete_product, get_product_by_id, get_products_with_cursor, query_products_with_cursor, update_product};
use crate::graphql::AuthGuard;


#[derive(SimpleObject)]
pub struct ProductConnection {
    pub products: Vec<ProductObject>,
    pub has_next: bool,
    pub next_cursor: Option<String>,
}

#[derive(Debug, Clone, SimpleObject)]
pub struct ProductSpecificationObject {
    pub id: String,
    pub product_id: String,
    pub item: String,
    pub value: String,
    pub create_time: String,
    pub update_time: String,
}

impl From<product_specification::Model> for ProductSpecificationObject {
    fn from(model: product_specification::Model) -> Self {
        Self {
            id: model.id.to_string(),
            product_id: model.product_id.to_string(),
            item: model.item,
            value: model.value,
            create_time: model.create_time.format("%Y-%m-%d %H:%M:%S").to_string(),
            update_time: model.update_time.format("%Y-%m-%d %H:%M:%S").to_string(),
        }
    }
}


#[derive(Debug, Clone, SimpleObject)]
pub struct ProductObject {
    pub id: String,
    pub title: String,
    pub cover_addr: String,
    pub description: String,
    pub price: String,
    pub create_time: String,
    pub update_time: String,
    pub rate: String,
    pub detail_addr: String,
    pub stockpile: u32,
    pub stockpile_frozen: u32,
    pub status: String,
    pub specifications: Vec<ProductSpecificationObject>,
}

impl From<product_main::Model> for ProductObject {
    fn from(model: product_main::Model) -> Self {
        Self {
            id: model.id.to_string(),
            title: model.title,
            description: model.description,
            price: model.price.to_string(),
            create_time: model.create_time.format("%Y-%m-%d %H:%M:%S").to_string(),
            update_time: model.update_time.format("%Y-%m-%d %H:%M:%S").to_string(),
            rate: model.rate.to_string(),
            detail_addr: model.detail_addr,
            cover_addr: model.cover_addr,
            status: model.status,
            stockpile: model.stockpile,
            stockpile_frozen: model.stockpile_frozen,
            specifications: Vec::new(),
        }
    }
}

#[derive(Default)]
pub struct ProductQuery;

#[Object]
impl ProductQuery {
    async fn product_list(
        &self,
        ctx: &Context<'_>,
        cursor: Option<String>,
        limit: u32,
    ) -> Result<ProductConnection> {
        let db = ctx.data::<DatabaseConnection>()?;
        

        get_products_with_cursor(db, cursor, limit).await
    }

    async fn query_product_list(
        &self,
        ctx: &Context<'_>,
        keyword: String,
        cursor: Option<String>,
        limit: u32,
    ) -> Result<ProductConnection> {
        let db = ctx.data::<DatabaseConnection>()?;
        let meilisearch = ctx.data::<Client>()?;

        query_products_with_cursor(db, meilisearch, keyword, cursor, limit).await
    }
    
    async fn product_by_id(
        &self,
        ctx: &Context<'_>,
        id: String,
    ) -> Result<Option<ProductObject>> {
        let db = ctx.data::<DatabaseConnection>()?;
        get_product_by_id(db, id).await
    }
}

// 添加产品规格输入类型
#[derive(InputObject)]
pub struct ProductSpecificationInput {
    pub item: String,
    pub value: String,
}

// 添加产品创建输入类型
#[derive(InputObject)]
pub struct CreateProductInput {
    pub title: String,
    pub cover_addr: String,
    pub description: String,
    pub price: String,
    pub rate: String,
    pub detail_addr: String,
    pub stockpile: u32,
    pub status: String,
    pub specifications: Option<Vec<ProductSpecificationInput>>,
}

// 修改产品更新输入类型，添加规格更新支持
#[derive(InputObject)]
pub struct UpdateProductSpecificationInput {
    pub id: Option<String>, // 如果提供ID则是更新现有规格，否则是新增规格
    pub item: String,
    pub value: String,
}

// 添加产品更新输入类型
#[derive(InputObject)]
pub struct UpdateProductInput {
    pub title: Option<String>,
    pub cover_addr: Option<String>,
    pub description: Option<String>,
    pub price: Option<String>,
    pub rate: Option<String>,
    pub detail_addr: Option<String>,
    pub stockpile: Option<u32>,
    pub status: Option<String>,
    pub specifications: Option<Vec<UpdateProductSpecificationInput>>, // 添加规格更新字段

}

// 在ProductQuery之后添加ProductMutation
#[derive(Default)]
pub struct ProductMutation;

#[Object]
impl ProductMutation {

    #[graphql(guard = "AuthGuard(\"product:create\")")]
    async fn create_product(
        &self,
        ctx: &Context<'_>,
        input: CreateProductInput,
    ) -> Result<ProductObject> {
        let db = ctx.data::<DatabaseConnection>()?;
        let meilisearch = ctx.data::<Client>()?;
        create_product(db, meilisearch, input).await
    }

    #[graphql(guard = "AuthGuard(\"product:update\")")]
    async fn update_product(
        &self,
        ctx: &Context<'_>,
        id: String,
        input: UpdateProductInput,
    ) -> Result<ProductObject> {
        let db = ctx.data::<DatabaseConnection>()?;
        let meilisearch = ctx.data::<Client>()?;
        update_product(db, meilisearch,  id, input).await
    }

    #[graphql(guard = "AuthGuard(\"product:delete\")")]
    async fn delete_product(
        &self,
        ctx: &Context<'_>,
        id: String,
    ) -> Result<bool> {
        let db = ctx.data::<DatabaseConnection>()?;
        let meilisearch = ctx.data::<Client>()?;
        delete_product(db, meilisearch, id).await
    }
}